﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Telerik.WinControls;
using Telerik.WinControls.Data;
using Telerik.WinControls.UI;
using MN.Framework.Common;
using MN.Framework.Common.Service;
using MN.Framework.Extensions;
using System.Globalization;
using MN.Framework.UI.Win.Forms;
using MN.Framework.UI.Win.Controls;

namespace MN.Framework.UI.Win
{
    public class MnFormEntity<EntityType> : Panel where EntityType : BaseEntity
    {
        public MnFormEntity(BaseContext context, int width, IBaseView<EntityType> winView)
        {
            WinView = winView;
            Context = context;
            Width = width;
            Columns = WinView.GetColumns();
            InitializeComponent();
            SetUIProperties();
        }
        public MnFormEntity(BaseContext context, int width)
        {
            Context = context;
            Width = width;
            Columns = ServiceFactory.GetColumns<EntityType>();
            InitializeComponent();
            SetUIProperties();
        }

        #region Properties
        IBaseView<EntityType> WinView { get; set; }
        List<ColumnInfo> Columns { get; set; }
        bool IsChanged { get; set; }
        BaseContext Context { get; set; }
        int LabelWidth { get { return this.Width * 30 / 100; } }
        int TextWidth { get { return this.Width * 70 / 100; } }
        MnLabel lblAlert { get; set; }
        TableLayoutPanel mainLayout;
        #endregion

        #region Method
        private void InitializeComponent()
        {

            mainLayout = new TableLayoutPanel();
            mainLayout.RowCount = Columns.Count;
            int RowCount = 0;
            var ControlWidth = (this.Width * 2) / 3;//  columns.Select(c => (int)c.Size).Sum();            
            foreach (var clmn in Columns)
            {
                MnLabel lbl = new MnLabel();
                lbl.Width = this.Width / 3;
                lbl.Text = clmn.HeaderText;
                mainLayout.Controls.Add(lbl, 0, RowCount);
                switch (clmn.Type)
                {
                    case ColumnType.Text:
                        MnTextBox txt = new MnTextBox();
                        txt.Name = clmn.Name;
                        txt.Width = ControlWidth;
                        txt.MaxLength = clmn.MaxLength;
                        if (clmn.Size == ColumnSize.XLarg || clmn.Size == ColumnSize.XXLarg)
                        {
                            txt.BackColor = Color.Red;
                            txt.Multiline = true;
                            txt.Height = txt.Height * 3;
                        }
                        txt.KeyPress += delegate(object sender, KeyPressEventArgs e)
                        {
                            IsChanged = true;
                        };
                        mainLayout.Controls.Add(txt, 1, RowCount);
                        break;
                    case ColumnType.Numeric:
                        MnMaskedEditBox mtxt = new MnMaskedEditBox();
                        mtxt.Name = clmn.Name;
                        mtxt.MaskType = MaskType.Numeric;
                        mtxt.Width = ControlWidth;
                        //if (clmn.Name == "ID")
                        mtxt.ReadOnly = clmn.ReadOnly;
                        mtxt.KeyPress += delegate(object sender, KeyPressEventArgs e)
                        {
                            IsChanged = true;
                        };
                        mainLayout.Controls.Add(mtxt, 1, RowCount);
                        break;
                    case ColumnType.Boolean:
                        MnCheckBox checkbox = new MnCheckBox();
                        checkbox.Name = clmn.Name;
                        checkbox.Click += delegate(object sender, EventArgs e)
                        {
                            IsChanged = true;
                        };
                        mainLayout.Controls.Add(checkbox, 1, RowCount);
                        break;
                    case ColumnType.DateTime:
                        MnDateTimePicker date = new MnDateTimePicker();
                        date.Name = clmn.Name;
                        date.Width = ControlWidth;
                        date.KeyPress += delegate(object sender, KeyPressEventArgs e)
                        {
                            IsChanged = true;
                        };
                        mainLayout.Controls.Add(date, 1, RowCount);
                        break;
                    case ColumnType.PersianDate:
                        MnDateTimePicker pdate = new MnDateTimePicker();
                        pdate.Name = clmn.Name;
                        pdate.Width = ControlWidth;
                        pdate.Culture = new PersianCulture();
                        pdate.ValueChanged += delegate(object sender, EventArgs e)
                        {
                            IsChanged = true;
                        };
                        mainLayout.Controls.Add(pdate, 1, RowCount);
                        break;
                    case ColumnType.Image:
                        MnPictureBox imgBox = new MnPictureBox();
                        imgBox.Name = clmn.Name;
                        imgBox.SizeMode = PictureBoxSizeMode.CenterImage;
                        imgBox.Width = ControlWidth;
                        //imgBox.Height = ControlWidth;
                        imgBox.BackgroundImage = MN.Framework.UI.Resource.ResourceImages.SelectImage;
                        imgBox.BackgroundImageLayout = ImageLayout.Stretch;
                        imgBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
                        imgBox.Click += imgBox_Click;
                        mainLayout.Controls.Add(imgBox, 1, RowCount);
                        break;
                    case ColumnType.Lookup:
                        MnDropDownList lookup = new MnDropDownList();
                        lookup.Name = clmn.Name;
                        lookup.DataMember = clmn.Name;
                        lookup.ValueMember = "Key";
                        lookup.DisplayMember = "Value";
                        lookup.DataSource = (clmn as LookupColumnInfo).LookupValues;
                        lookup.SelectedIndexChanged += delegate(object sender, Telerik.WinControls.UI.Data.PositionChangedEventArgs e)
                        {
                            IsChanged = true;
                        };
                        mainLayout.Controls.Add(lookup, 1, RowCount);

                        break;
                    case ColumnType.State:
                        break;
                    case ColumnType.EntityCode:
                        break;
                    case ColumnType.Transformer:
                        break;
                    case ColumnType.Refrence:
                        var selector = new MnSelector(typeof(EntityType), clmn, Context, ControlWidth);
                        selector.SelectedIndexChanged += delegate(object sender, Telerik.WinControls.UI.Data.PositionChangedEventArgs e)
                        {
                            IsChanged = true;
                        };
                        mainLayout.Controls.Add(selector, 1, RowCount);
                        #region oldRefrence
                        //var refInstance = ServiceFactory.CreateRelatedEntity<EntityType>(clmn.Name);
                        //MnMultiColumnComboBox lookup = new MnMultiColumnComboBox();
                        //lookup.ValueMember = "ID";
                        //lookup.Name = clmn.Name;
                        //lookup.Width = ControlWidth;
                        //lookup.MultiColumnComboBoxElement.DropDownWidth = 300;
                        //Api.DetailGridColumnsGenerator<EntityType>(lookup.MultiColumnComboBoxElement.Columns, this.Width, refInstance, Context);
                        //var list = Context.RelationEntity<EntityType>(clmn.Name);
                        //lookup.DataSource = list;
                        //#region lookup.Filter
                        //lookup.AutoFilter = true;
                        //lookup.DisplayMember = refInstance.FirstOrDefaultDisplayField();
                        //FilterDescriptor filter = new FilterDescriptor();
                        //filter.PropertyName = refInstance.DefaultFilterField();
                        //filter.Operator = FilterOperator.Contains;
                        //lookup.EditorControl.MasterTemplate.FilterDescriptors.Add(filter);
                        //#endregion                   
                        //this.Controls.Add(lookup, 1, RowCount); 
                        #endregion
                        break;
                    default:
                        break;
                }
                RowCount++;
            }

            mainLayout.Controls.Add(lblAlert = new MnLabel(), 0, RowCount);
            #region save button
            MnButton btnSave = new MnButton();
            btnSave.Text = Resource.Core.BtnSaveTitle;
            btnSave.Click += btnSave_Click;
            mainLayout.Controls.Add(btnSave, 0, RowCount + 1);
            #endregion
            #region new item
            MnButton btnNew = new MnButton();
            btnNew.Text = Resource.Core.BtnNewTitle;
            btnNew.Click += btnNew_Click;
            mainLayout.Controls.Add(btnNew, 1, RowCount + 1);
            #endregion
            this.Controls.Add(mainLayout);
        }

        public void SetUIProperties()
        {
            //this.Width = Parent != null ? Parent.Width : 250;
            this.Dock = DockStyle.Fill;
            mainLayout.Dock = DockStyle.Fill;
            mainLayout.ColumnCount = 2;
            this.AutoScroll = true;
            this.IsChanged = false;
        }
        object getControlValue(string Name)
        {
            var control = this.Controls.Find(Name, true).First();

            if (control is IMnControl)
            {
                return ((IMnControl)control).getValue();
            }
            else
                throw new Exception("Control 'getValue' method undefined");
            //if (control.GetType() == typeof(MnMaskedEditBox))
            //{
            //    return (control as MnMaskedEditBox).Text;
            //}
            //else if (control.GetType() == typeof(MnTextBox))
            //{
            //    return (control as MnTextBox).Text;
            //}
            //else if (control.GetType() == typeof(MnMultiColumnComboBox))
            //{
            //    return (control as MnMultiColumnComboBox).SelectedValue;
            //}
            //else if (control.GetType() == typeof(MnDropDownList))
            //{
            //    return (control as MnDropDownList).SelectedValue;
            //}
            //else if (control.GetType() == typeof(PictureBox))
            //{
            //    return (control as PictureBox).InitialImage.ToByteArray();
            //}
            //else if (control.GetType() == typeof(MnSelector))
            //{
            //    return (control as MnSelector).SelectedValue;
            //}
            //else if (control.GetType() == typeof(MnDateTimePicker))
            //{
            //    var dt = (control as MnDateTimePicker).Value;
            //    System.Globalization.PersianCalendar shamsi = new System.Globalization.PersianCalendar();
            //    return string.Format("{0}/{1}/{2}", shamsi.GetYear(dt), shamsi.GetMonth(dt), shamsi.GetDayOfMonth(dt));
            //}            
        }
        public void DataBind(int ID)
        {
            IsChanged = false;
            var dbrow = Context.Set<EntityType>().SingleOrDefault(r => r.ID == ID);
            for (int i = 0; i < Columns.Count; i++)
            {
                if (this.Controls.Find(Columns[i].Name, true).Any())
                {
                    var fControl = this.Controls.Find(Columns[i].Name, true).First();
                    var dbValue = dbrow.GetType().GetProperty(Columns[i].Name).GetValue(dbrow);

                    if (fControl is IMnControl)
                    {
                        (fControl as IMnControl).setValue(dbValue);
                        //if (fControl is MnMultiColumnComboBox)
                        //{
                        //    ((MnMultiColumnComboBox)fControl).
                        //        SelectedValue = dbValue;
                        //}
                        //else if (fControl is MnDropDownList)
                        //{
                        //    ((MnSelector)fControl).
                        //        SelectedValue = dbValue;
                        //}
                        //else if (fControl is MnCheckBox)
                        //{
                        //    ((MnCheckBox)fControl).Checked = (bool)dbValue;
                        //}
                        //else
                        //{
                        //    if (dbValue != null)
                        //        fControl.Text = dbValue.ToString();
                        //}
                    }
                    else
                        throw new Exception("setValue method undefined");
                }
            }

        }
        #endregion

        #region events
        public virtual event EventHandler<int> SaveComplated;

        void btnNew_Click(object sender, EventArgs e)
        {
            foreach (var control in this.Controls)
            {
                if (control is TableLayoutPanel)
                {
                    foreach (var ccontrol in (control as TableLayoutPanel).Controls)
                        if ((ccontrol is MnTextBox) || (ccontrol is MnMaskedEditBox))
                            (ccontrol as RadControl).ResetText();
                }
                else if (control is RadControl)
                {
                    if ((control is MnTextBox) || (control is MnMaskedEditBox))
                        (control as RadControl).ResetText();
                }

            }
        }
        //void element_PopupOpening(object sender, CancelEventArgs e)
        //{
        //    MnMultiColumnComboBoxElement element = sender as MnMultiColumnComboBoxElement;
        //    element.MultiColumnPopupForm.MinimumSize = new Size(this.Width / 2, this.Height / 2);
        //    element.MultiColumnPopupForm.RightToLeft = System.Windows.Forms.RightToLeft.Yes;
        //    element.MultiColumnPopupForm.HorizontalPopupAlignment = HorizontalPopupAlignment.RightToLeft;
        //    element.EditorControl.GridViewElement.MinSize = new Size(this.Width / 2, this.Height / 2);
        //    element.MultiColumnPopupForm.Width = this.Width / 2;
        //}

        //string lastText = string.Empty;
        //string lastValue = string.Empty;
        //void multiComboElement_TextChanged(object sender, EventArgs e)
        //{

        //    var multiComboElement = sender as MnMultiColumnComboBoxElement;
        //    //if (!multiComboElement.EditorControl.MasterGridViewTemplate.FilterExpressions.Any())
        //    //    EditoInitialized(multiComboElement);

        //    string propertyName = multiComboElement.EditorControl.MasterGridViewTemplate.FilterExpressions[0].PropertyName;
        //    string propertyValue = multiComboElement.Text.Trim();

        //    if (multiComboElement.Value == null || multiComboElement.Value != lastValue)
        //    {
        //        if (!string.IsNullOrEmpty(propertyValue) && (string.IsNullOrEmpty(lastText) || !lastText.Contains(propertyValue)))
        //        {
        //            multiComboElement.DataSource = Context.RelationEntity<EntityType>(multiComboElement.Name).WhereQuery(propertyName, propertyValue).ToList();
        //            lastText = propertyValue;
        //            if (multiComboElement.Value != null)
        //                lastValue = multiComboElement.Value.ToString();
        //        }
        //    }
        //}

        void imgBox_Click(object sender, EventArgs e)
        {

            ImageCropForm photoForm = new ImageCropForm(sender);
            photoForm.ShowDialog();
            IsChanged = true;
            //// open file dialog 
            //OpenFileDialog open = new OpenFileDialog();
            //// image filters
            //open.Filter = "Image Files(*.jpg; *.jpeg; *.gif; *.bmp)|*.jpg; *.jpeg; *.gif; *.bmp";
            //if (open.ShowDialog() == DialogResult.OK)
            //{
            //    // display image in picture box
            //    ((PictureBox)sender).Image = new Bitmap(open.FileName);
            //    // image file path
            //    //textBox1.Text = open.FileName;
            //}
        }

        void btnSave_Click(object sender, EventArgs e)
        {
            var ID = int.Parse(((MnMaskedEditBox)this.Controls.Find("ID", true).First()).Text);
            if (ID != 0)
            {
                if (IsChanged)
                {
                    EntityType obj = Context.Set<EntityType>().Find(ID);
                    foreach (var clmn in Columns)
                    {
                        if (!clmn.ReadOnly)
                        {
                            if (getControlValue(clmn.Name) != null)
                            {

                                if (IsChanged)
                                {
                                    typeof(EntityType).GetProperty(clmn.Name).SetValue(obj, Convert.ChangeType(getControlValue(clmn.Name), clmn.BaseType));
                                }
                            }
                        }
                    }
                    Context.SaveChanges();
                    SaveComplated(this, ID);
                }
                else
                    MnMessageBox.ShowAlertBox("تغییری در اطلاعات اولیه ایجاد نشده است \n برای ذخیره باید حتما یکی از مقادیر این موجودیت تغییر نماید.", "عدم ذخیره");
            }
            else
            {
                EntityType obj = Context.Set<EntityType>().Create();
                foreach (var clmn in Columns)
                {
                    if (!clmn.ReadOnly)
                    {
                        if (this.Controls.Find("ID", true).Any())
                        {
                            var type = clmn.BaseType;
                            typeof(EntityType).GetProperty(clmn.Name).
                                   SetValue(obj, Convert.ChangeType(getControlValue(clmn.Name), type));
                        }
                    }
                }
                Context.Set<EntityType>().Add(obj);
                Context.SaveChanges();
                SaveComplated(this, ID);
            }
        }
        #endregion


    }
}
